﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using CommonClasses.Model;
using Eco.Handles;
using CommonClasses.Utility;
using System.IO;
using System.Windows.Forms;
using Eco.ObjectRepresentation;
using Eco.Services;
using EcoExtensions.Model;
using CommonClasses.Logger;

namespace Project.Model
{
    internal static class FactoryPluginUtility
    {
        
        private static Dictionary<string, Assembly> codebases = new Dictionary<string, Assembly>();

        /// <summary>
        /// Загрузить все типы документов из файла и их фабрики из сборок
        /// </summary>
        /// <param name="serviceProvider">служебное поле для работы с Eco-объектом</param>
        /// <param name="cfg">путь к файлу с типами документов</param>
        /// <param name="loggingManagement">менеджмент для создания логгеров</param>
        /// <returns>типы документов (с фабриками)</returns>
        static public IList<DocumentType> LoadDocumentTypesFromFile(IEcoServiceProvider serviceProvider, string cfg, ILoggingManagement loggingManagement)
        {
            var loader = new ProjectLoader(serviceProvider, QueriesDirectory);
            //TODO: вставить загрузку

            PathUtility.RestoreCurrentDirectory(Locality.ExeFile);
            loader.LoadDocumentTypesFromFile(cfg);

            // в следующей строке из файла Plugins.ih.config
            // считаются и создадутся все типы документов
            PathUtility.RestoreCurrentDirectory(Locality.ExeFile);
            var knownplugins = serviceProvider.GetEcoService<IOclService>().Evaluate("DocumentType.allInstances").GetAsIList<DocumentType>();
            foreach (var plugingdata in knownplugins)
            {
                foreach (var factoryclassname in plugingdata.FactoryClassNames)
                    plugingdata.Factories.Add(
                      LoadFactoryAssembly(
                      plugingdata.Assemblies[plugingdata.FactoryClassNames.IndexOf(factoryclassname)].String, factoryclassname.String,
                      serviceProvider, loggingManagement));
            }
            return knownplugins;
        }

        /// <summary>
        /// Загрузить сборку с фабрикой
        /// </summary>
        /// <param name="path">путь к сборке</param>
        /// <param name="FactoryClassName">название класса, реализующего интерфейс фабрики</param>
        /// <param name="serviceProvider">служебное поле для работы с Eco-объектом</param>
        /// <param name="loggingManagment">управление логгерами</param>
        /// <returns></returns>
        static private EcoObject LoadFactoryAssembly(string path, string FactoryClassName,IEcoServiceProvider serviceProvider, ILoggingManagement loggingManagment)
        {
            var ecoObject = new EcoObject(serviceProvider);

            Assembly assembly;
            if (codebases.ContainsKey(path) == false)
            {
                assembly = Assembly.LoadFrom(path);
                codebases.Add(path, assembly);
            }
            else
                assembly = codebases[path];


            var doctype = assembly.GetType(FactoryClassName, true);
            if (doctype == null)
            {
                throw new Exception("Компонент " + FactoryClassName + " не найден в сборке " + path);
                //logger.WriteMessage(LogManager.MessagePriority.Error, "Компонент " + Setting.Name + " не найден в сборке " + Setting.Path_to_dll);
                return null;
            }
            var factory = (IDocumentsFactory)Activator.CreateInstance(doctype, serviceProvider, loggingManagment);
            if (factory == null)
            {
                throw new Exception("Ошибка при создании компонента " + FactoryClassName + " " + path);
                //logger.WriteMessage(LogManager.MessagePriority.Error, "Ошибка при создании компонента " + Setting.Name + " " + Setting.Path_to_dll);
                return null;
            }
            ecoObject.Object = factory;
            return ecoObject;
        }

        private const string QueriesDirectory = @".\queries\";
    }
}
